﻿using System;
using System.Collections.Generic;
using System.Linq;
using TestOnlineProject.Common;
using TestOnlineProject.Models.DataAccess;
using TestOnlineProject.Models.Entities;
using System.Web;

namespace TestOnlineProject.Models.BusinessLogic
{
    public class DiscussionBLO
    {
        DiscussionDAO discussionDAO = new DiscussionDAO();
        UserDAO userDAO = new UserDAO();
        SubjectDAO subjectDAO = new SubjectDAO();

        /// <summary>
        /// List Discussion in Subject
        /// </summary>
        /// <param name="subjectId">Id of Subject</param>
        /// <param name="userId">Id of User</param>
        /// <param name="keyWord">String to search Title</param>
        /// <param name="status">Staus of Discussion</param>
        /// <returns>List Discussion</returns>

        public List<DiscussionModel> ToList(int subjectId, int userId, string keyWord, string status)
        {
            try
            {
                var discussionModels = new List<DiscussionModel>();
                keyWord = keyWord.Trim().ToLower();
                List<Discussion> discussions;

                // Get list discussion with subjectId
                if (subjectId == 0)
                {
                    discussions = discussionDAO.Select();
                }
                else
                {
                    discussions = discussionDAO.SelectBySubjectId(subjectId);
                }

                // Get list discussion active
                if(!HttpContext.Current.User.IsInRole("1"))
                {
                    discussions = discussions.Where(x => x.IsActivated).ToList();
                }

                // Get list discussion with userId
                if (userId != 0)
                {
                    discussions = discussions.Where(x => x.UserId == userId).ToList();
                }

                // Get list disscussion with keyWord
                if (keyWord != "")
                {
                    discussions = discussions.Where(x => x.Title.ToLower().Contains(keyWord)).OrderByDescending(x => x.LastEditedTime).ToList();
                }

                // Get list discussion with status
                if (status.Equals("All"))
                {
                    discussions = discussions.Where(x => x.ParentId == null).ToList();
                }

                if (status.Equals("False"))
                {
                    discussions = discussions.Where(x => !x.IsActivated).ToList();
                }

                // Add each Discussion to DiscussionModel
                foreach (var discussion in discussions)
                {
                    var startUser = userDAO.SelectByUserId(discussion.UserId);

                    var discussionModel = new DiscussionModel
                    {
                        Discussion = discussion,
                        User = startUser,
                        Subject = subjectDAO.SelectBySubjectId(discussion.SubjectId)
                    };

                    // Add TotalReplies
                    var replies = discussionDAO.SelectByParentId(discussion.DiscussionId)
                                                .OrderBy(x => x.LastEditedTime)
                                                .ToList();
                    discussionModel.TotalReplies = replies.Count;

                    if (replies.Count > 0)
                    {
                        var lastPost = replies.LastOrDefault();
                        // Add LastPost
                        discussionModel.LastPost = lastPost.LastEditedTime.ToShortDateString() + ", " +
                                                   lastPost.LastEditedTime.ToShortTimeString();

                        // Add LastUser
                        var lastUser = userDAO.SelectByUserId(lastPost.UserId);
                        discussionModel.LastUser = lastUser.Username;
                        discussionModel.LastDiscussion = lastPost.DiscussionId;
                    }
                    else
                    {
                        discussionModel.LastPost = discussion.LastEditedTime.ToShortDateString() + ", " +
                                                   discussion.LastEditedTime.ToShortTimeString();
                        discussionModel.LastUser = startUser.Username;
                        discussionModel.LastDiscussion = discussion.DiscussionId;
                    }

                    // Add DiscussionModel to List DiscussionModel
                    discussionModels.Add(discussionModel);
                }
                return discussionModels;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// List all Discussion in Subject
        /// </summary>
        /// <returns>List Discussion</returns>

        public List<Discussion> ToList()
        {
            try
            {
                var discussions = discussionDAO.Select();
                if (!HttpContext.Current.User.IsInRole("1"))
                {
                    discussions = discussions.Where(x => x.IsActivated).ToList();
                }

                return discussions;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public List<Discussion> Recommend()
        {
            try
            {
                var list = discussionDAO.Select().Where(d => d.ParentId == null && d.IsActivated).OrderByDescending(d => d.DiscussionId).ToList();
                if (!HttpContext.Current.User.IsInRole("1"))
                {
                    list = list.Where(d => d.Subject.Participants.Where(p => p.IsActivated && p.UserId == int.Parse(HttpContext.Current.User.Identity.Name)).ToList().Count > 0 && d.Subject.IsActivated).ToList();
                }
                return list;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get Details of Discussion
        /// </summary>
        /// <param name="discussionId">Id of Discussion</param>
        /// <param name="thread">Id of Discussion to OnTop</param>
        /// <returns>Discussion object</returns>

        public DiscussionModel Find(int discussionId, int thread)
        {
            try
            {
                DiscussionModel discussionModel;

                // Get Value
                var discussion = discussionDAO.SelectByDiscussionId(discussionId);

                if (discussion.ParentId != null)
                {
                    var parentId = (int)discussion.ParentId;
                    var parentDiscussion = discussionDAO.SelectByDiscussionId(parentId);
                    discussionModel = GenerateDiscussionModel(parentDiscussion, thread);
                }
                else
                {
                    discussionModel = GenerateDiscussionModel(discussion, thread);
                }

                return discussionModel;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Generate DiscussionModel
        /// </summary>
        /// <param name="discussion">Discussion object</param>
        /// <param name="thread">Id of Discussion will be ontop</param>
        /// <returns>DiscussionModel object</returns>

        public DiscussionModel GenerateDiscussionModel(Discussion discussion, int thread)
        {
            try
            {
                var user = userDAO.SelectByUserId(discussion.UserId);
                var subject = subjectDAO.SelectBySubjectId(discussion.SubjectId);

                var discussionModel = new DiscussionModel
                {
                    Discussion = discussion,
                    User = user,
                    Subject = subject
                };

                if (thread == discussion.DiscussionId)
                {
                    discussionModel.OnTop = true;
                }

                // Add Replies
                var replies = discussionDAO.SelectByParentId(discussion.DiscussionId).ToList();
                foreach (var item in replies)
                {
                    var userReply = userDAO.SelectByUserId(item.UserId);
                    var reply = new DiscussionModel
                    {
                        Discussion = item,
                        User = userReply
                    };
                    if (thread == item.DiscussionId)
                    {
                        reply.OnTop = true;
                    }
                    discussionModel.Replies.Add(reply);
                }

                return discussionModel;

            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Find Discussion by Id
        /// </summary>
        /// <param name="discussionId">Id of Discussion</param>
        /// <returns>Discussion object</returns>

        public Discussion Find(int discussionId)
        {
            try
            {
                var discussion = discussionDAO.SelectByDiscussionId(discussionId);
                return discussion;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Create new Discussion
        /// </summary>
        /// <param name="subjectId">Id of Subject</param>
        /// <param name="title">Title of Discussion</param>
        /// <param name="message">Message of Discussion</param>
        /// <returns>Discussion object has been added</returns>

        public Discussion CreateDiscussion(int subjectId, string title, string message)
        {
            try
            {
                // Add Value of Discussion
                var discussion = new Discussion
                {
                    SubjectId = subjectId,
                    Title = title.Trim(),
                    Content = message,
                    UserId = Int32.Parse(HttpContext.Current.User.Identity.Name),
                    CreatedTime = DateTime.Now,
                    LastEditedTime = DateTime.Now,
                    IsActivated = true
                };

                // Insert to Database
                var result = discussionDAO.Insert(discussion);
                if (result > 0)
                {
                    return discussion;
                }
                return null;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Create Reply Discussion
        /// </summary>
        /// <param name="discussionModel">Discussion Object</param>
        /// <param name="message">Content of Reply</param>
        /// <returns>Number of reply has been created</returns>

        public int CreateReply(DiscussionModel discussionModel, string message)
        {
            try
            {
                var discussion = discussionDAO.SelectByDiscussionId(discussionModel.Discussion.DiscussionId);
                if (discussion == null || !discussion.IsActivated)
                {
                    return -1;
                }

                // Add Value of Reply
                var reply = new Discussion
                {
                    SubjectId = discussionModel.Subject.SubjectId,
                    ParentId = discussionModel.Discussion.DiscussionId,
                    Title = "Re: " + discussionModel.Discussion.Title,
                    Content = message,
                    UserId = Int32.Parse(HttpContext.Current.User.Identity.Name),
                    CreatedTime = DateTime.Now,
                    LastEditedTime = DateTime.Now,
                    IsActivated = true
                };

                // Insert to Database
                var result = discussionDAO.Insert(reply);
                if (result > 0)
                {
                    return result;
                }
                return 0;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Modify Discussion
        /// </summary>
        /// <param name="discussionId">Id of Discussion</param>
        /// <param name="content">Content of Discussion</param>
        /// <returns>Number of Discussion has been modify</returns>

        public int Modify(int discussionId, string content)
        {
            try
            {
                // Select Discussion with discussionId
                var discussion = discussionDAO.SelectByDiscussionId(discussionId);

                if (discussion == null)
                {
                    return -1;
                }

                if (!discussion.IsActivated)
                {
                    return -2;
                }

                if (discussion.ParentId != null)
                {
                    var parentId = (int)discussion.ParentId;
                    var parentDiscussion = discussionDAO.SelectByDiscussionId(parentId);
                    if (!parentDiscussion.IsActivated)
                    {
                        return -3;
                    }
                }

                // Modify Discussion
                discussion.Content = content;
                discussion.LastEditedTime = DateTime.Now;

                // Update to Database
                var result = discussionDAO.Update(discussion);
                return result;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Delete Reply
        /// </summary>
        /// <param name="discussionId">Id of Discussion</param>
        /// <returns>Number of Discussion has been delete</returns>

        public int RemoveReply(int discussionId)
        {
            try
            {
                // Select Discussion by discussionId
                var discussion = discussionDAO.SelectByDiscussionId(discussionId);

                if (discussion == null)
                {
                    return -1;
                }

                // Delete Discussion in Database
                var result = discussionDAO.Delete(discussion);
                return result;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Checking duplicate Title of new Discussion
        /// </summary>
        /// <param name="subjectId">Id of Subject</param>
        /// <param name="title">String title</param>
        /// <returns>Duplicate title or not</returns>

        public bool CheckingTitle(int subjectId, string title)
        {
            try
            {
                // Get all Discussion in Subject
                var discussions = discussionDAO.SelectBySubjectId(subjectId).ToList();

                // Checking Title
                for (var i = 0; i < discussions.Count(); i++)
                {
                    var oldTitle = discussions[i].Title.ToLower();
                    if (title.Trim().ToLower().Equals(oldTitle))
                    {
                        return false;
                    }
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Deactivate Discussion
        /// </summary>
        /// <param name="ids">List Id of Discussion</param>
        /// <returns>Number of Discussion has been deactivate</returns>

        public int Deactivate(string ids = "")
        {
            // Split id string to int array.
            var spliter = new StringHelper();
            var idInt = spliter.Split(ids);

            var result = 0;
            // Deactivate Discussion.
            foreach (var id in idInt)
            {
                // Select Discussion by Id.
                var discussion = discussionDAO.SelectByDiscussionId(id);
                if (discussion == null)
                {
                    return -1;
                }

                // Check Discussion is activated?
                if (discussion.IsActivated)
                {
                    discussion.IsActivated = false;
                    result += discussionDAO.Update(discussion);
                }
                else
                {
                    result += 1;
                }
            }

            return result;
        }

        /// <summary>
        /// Activate Discussion
        /// </summary>
        /// <param name="ids">List Id of Discussion</param>
        /// <returns>Number of Discussion has been Activate</returns>

        public int Activate(string ids = "")
        {
            // Split id string to int array.
            var spliter = new StringHelper();
            var idInt = spliter.Split(ids);

            var result = 0;
            // Activate Discussion.
            foreach (var id in idInt)
            {
                // Select Discussion by Id.
                var discussion = discussionDAO.SelectByDiscussionId(id);
                if (discussion == null)
                {
                    return -1;
                }

                // Check Discussion is deactivated?
                if (!discussion.IsActivated)
                {
                    discussion.IsActivated = true;
                    result += discussionDAO.Update(discussion);
                }
                else
                {
                    result += 1;
                }
            }

            return result;
        }

        /// <summary>
        /// Remove Discussion
        /// </summary>
        /// <param name="ids">List Id of Discussion</param>
        /// <returns>Number of Discussion has been remove</returns>

        public int Remove(string ids = "")
        {
            // Split id string to int array.
            var spliter = new StringHelper();
            var idInt = spliter.Split(ids);

            var result = 0;

            // Activate subjects.
            foreach (var id in idInt)
            {
                // Select Discussion by Id.
                var discussion = discussionDAO.SelectByDiscussionId(id);

                if (discussion != null)
                {
                    // Select replies of Discussion
                    var replies = discussionDAO.SelectByParentId(id);

                    // Delete Replies
                    if (replies != null)
                    {
                        foreach (var reply in replies)
                        {
                            discussionDAO.Delete(reply);
                        }
                    }

                    // Delete Discussion
                    result += discussionDAO.Delete(discussion);
                }
            }

            return result;
        }
    }
}